﻿# Aby zmienic LOAD na qsize zamiast qsize/url_per_tick, wystarczy zakomentowac niezakomentowane i odkomentowac zakomentowane linie miedzy
# # # # START
# a
# # # # END

import spade
from LBCrawlerAgent import LBCrawlerAgent
from CrawlerAgent import MyPeriodicBehaviour
import random

_show_function_calls = True


  ##################################################################
  ## RandomLBCrawlerAgent                                         ##
  ##################################################################

class RandomLBCrawlerAgent(LBCrawlerAgent): # agent z consistent hashing i losowym LB
  class SendLoadToRandomAgents(MyPeriodicBehaviour): # zachowanie wysylajace co jakis czas qsize#urls_per_tick do losowych max_agents agentow
    def __init__(self, period, timestart=0, max_agents=1):
      MyPeriodicBehaviour.__init__(self, period, timestart)
      self.max_agents_to_consult = max_agents

    def _onTick(self):
      if _show_function_calls:
        print '\t+SendLoadToRandomAgents'
      if self.myAgent.rlb_agents == []:
        return
##      print self.myAgent.rlb_agents
      msg = spade.ACLMessage.ACLMessage()
      msg.setPerformative('cfp')
      msg.setOntology(self.myAgent.service_name)
      # # # START
      load = str(self.myAgent.url_queue.qsize()) + '#' + str(self.myAgent.avg_urls_per_tick)
##      load = self.myAgent.url_queue.qsize()
      # # # END
      msg.setContent(load)
      aname = self.myAgent.getName()
      sent_list = [aname]
      for i in xrange(min(self.max_agents_to_consult, len(self.myAgent.rlb_agents))):
        anum = len(self.myAgent.rlb_agents)
        while aname in sent_list:
          aname = self.myAgent.rlb_agents[random.randint(0, anum-1)]
        sent_list.append(aname)
        receiver = spade.AID.aid(name=aname, addresses=['xmpp://' + aname])
        msg.addReceiver(receiver)
##        print self.myAgent.getName(), '->', aname, ': load', load
      print '\t\tSTART'
      self.myAgent.add_stat_sent_msgs()
      self.myAgent.send(msg)
      if _show_function_calls:
        print '\t-SendLoadToRandomAgents'
  ##################################################################
  class ReceiveLoadAndRespod(spade.Behaviour.Behaviour):
    def _process(self):
      msg = None
      msg = self._receive()
      if msg:
        self.myAgent.add_stat_rcvd_msgs()
        if _show_function_calls:
          print '\t+ReceiveLoadAndRespond'
          # # # START
        rcvd_qsize, rcvd_upt = map(float, msg.getContent().split('#'))
        sender = msg.getSender()
##        print '\tReceiveLoadAndRespond', rcvd_qsize, rcvd_upt
        my_qsize, my_upt = map(float, [self.myAgent.url_queue.qsize(), self.myAgent.avg_urls_per_tick])
        diff2 = int((rcvd_qsize * my_upt - my_qsize * rcvd_upt) / (rcvd_upt + my_upt)) # ilosc urli, ktore agent otrzyma
##        rcvd_qsize = int(msg.getContent())
##        print '\tReceiveQsizeAndRespond ', rcvd_qsize
##        my_qsize = self.myAgent.url_queue.qsize()
##        print '\tI received qsize ', rcvd_qsize, ' from sender: ', msg.getSender().getName(), ', my qsize: ', my_qsize
##        if my_qsize < rcvd_qsize:
        if diff2 > 0: # agent ma mniej niz wysylajacy, wiec wysyla info ile chce dostac
          diff2 = min(diff2, int(rcvd_qsize / 2))
        # # # END
          rmsg = msg.createReply()
          # # # START
          rmsg.setContent(diff2)
##          rmsg.setContent((rcvd_qsize - my_qsize) / 2)
          # # # END
          rmsg.setPerformative('accept-proposal')
          self.myAgent.add_stat_sent_msgs()
          self.myAgent.send(rmsg)
          # # # START
        else: # agent ma wiecej niz wysylajacy, wiec wysyla urle
##        elif my_qsize > rcvd_qsize:
          diff2 = -diff2 # teraz diff to ilosc urli do wyslania
          diff2 = min(diff2, int(my_qsize / 2))
##          diff2 = (my_qsize - rcvd_qsize) / 2
          # # # END
          if diff2 > 0:
            self.myAgent.send_urls(diff2, sender)
          print '\t\tKONIEC'
        if _show_function_calls:
          print '\t-ReceiveLoadAndRespond'
  ##################################################################
  class ReceiveLBAcceptAndRespond(spade.Behaviour.Behaviour):
    def _process(self):
      msg = None
      msg = self._receive()
      if msg:
        self.myAgent.add_stat_rcvd_msgs()
        if _show_function_calls:
          print '\t+ReceiveLBAcceptAndRespond'
        diff2 = int(msg.getContent())
        sender = msg.getSender()
##        print '\tReceiveLBAcceptAndRespond', diff2
        self.myAgent.send_urls(diff2, sender)
        print '\t\tKONIEC'
        if _show_function_calls:
          print '\t-ReceiveLBAcceptAndRespond'
  ##################################################################
  def set_rlb_agents(self, agents):
    self.rlb_agents = agents
    print '#rlb', self.rlb_agents
  ##################################################################
  def _setup(self):
    self.rlb_agents = []

    self.service_name = 'random_lb'
    self.transfer_service_name = self.service_name + '_url_transfer'
    self.set_lb_agents = self.set_rlb_agents

    b = self.SendLoadToRandomAgents(self.behav_period, self.lb_timestart)
    self.addBehaviour(b)

    template = spade.Behaviour.ACLTemplate()
    template.setPerformative('cfp')
    template.setOntology(self.service_name)
    mt = spade.Behaviour.MessageTemplate(template)
    b = self.ReceiveLoadAndRespod()
    self.addBehaviour(b, mt)

    template = spade.Behaviour.ACLTemplate()
    template.setPerformative('accept-proposal')
    template.setOntology(self.service_name)
    mt = spade.Behaviour.MessageTemplate(template)
    b = self.ReceiveLBAcceptAndRespond()
    self.addBehaviour(b, mt)

    LBCrawlerAgent._setup(self)
